﻿using UnityEngine;
//using System;
using System.Collections;
using System.Collections.Generic;
//using System.Reflection;
#if UNITY_EDITOR
	using UnityEditor;
#endif

public class TroubleGame : GenericGame 
{
	//public List<string> m_AllMethods = new List<string>();
	[System.Serializable]
	public class m_ObjectivesClass
	{
		public string m_ObjectivesText;
		public m_ObjectivesIDEnum m_ObjectivesID;
	}
	public enum m_ObjectivesIDEnum
	{
		NONE = 0,
		COLLECTCOINS,
		MOSTKILLS,
		//CAPTUREBASE = 3,
		OBJECTIVESEND
	}

	public int m_CardsNumber = 3;
	public float m_CardsPositionSpeed = 5f;
	public float m_CardsOffsetYPercentage = 0.5f;
	public int m_CardsMinValue = 2;
	public int m_CardsMaxValue = 5;
	public float m_CPUDelayTime = 1f;
	public GameObject m_PlayerPrefab;
	public GameObject m_CardPrefab;
	public GameObject m_PopupScreen;
	public GameObject m_IconScorePrefab;
	public GameObject m_PlayerTurnText;
	public TextMesh m_ObjectivesText;
	public TextMesh m_TurnsLeftText;
	public m_ObjectivesClass[] m_Objectives;
	public m_ObjectivesIDEnum m_CurrentObjectives = m_ObjectivesIDEnum.NONE;
	public GameObject m_Coins;
	public GameObject[] m_LevelsForTwo;
	public GameObject[] m_LevelsForThreeAndMore;

	private TroubleCard m_CurrentCard;
	private List<EmptySquare> m_AllSquares = new List<EmptySquare>();
	private List<GameObject> m_CurrentCoins = new List<GameObject>();
	private List<TroublePlayer> m_Players = new List<TroublePlayer>();
	private TroublePlayer m_CurrentPlayer;
	private List<TroubleCard> m_CardsList = new List<TroubleCard>();
	private List<int> m_RandomPosList = new List<int>();
	private int m_CurrentTurn = 0;
	private bool m_CanClick = false;
	private bool m_EntranceAnimDone = false;
	private bool m_ExitAnimDone = false;
	private bool m_CanDestroyCards = false;
	private float m_CardsOffsetY;
	private int m_MovesLeft = 0;
	private int m_TurnsLeft;
	private bool m_TurnEnded = false;
	private bool m_GameOver = false;
	private List<GameObject> m_AllBases = new List<GameObject>();
	private List<GameObject> m_IconScore = new List<GameObject>();
	private int m_SquareListID = 0;
	
	public TroubleCard CurrentCard {get { return m_CurrentCard; } set { m_CurrentCard = value; }}
	public List<EmptySquare> AllSquares {get { return m_AllSquares; } set { m_AllSquares = value; }}
	public List<GameObject> CurrentCoins {get { return m_CurrentCoins; } set { m_CurrentCoins = value; }}
	public List<GameObject> IconScore {get { return m_IconScore; }}
	public List<TroublePlayer> Players {get { return m_Players; }}
	public TroublePlayer CurrentPlayer {get { return m_CurrentPlayer; }}
	public List<TroubleCard> CardsList {get { return m_CardsList; } set { m_CardsList = value; }}
	public int CurrentTurn {get { return m_CurrentTurn; } set { m_CurrentTurn = value; }}
	public bool CanClick {get { return m_CanClick; }}
	public int MovesLeft {get { return m_MovesLeft; } set { m_MovesLeft = value; }}
	public bool TurnEnded {get { return m_TurnEnded; }}
	public bool GameOver {get { return m_GameOver; }}
	public int SquareListID {get { return m_SquareListID; } set {m_SquareListID = value; }}

	protected override void Awake()
	{
		//Type thisType = (typeof (TroubleGame));
		//MethodInfo[] methInfo = thisType.GetMethods(BindingFlags.Public|BindingFlags.Instance|BindingFlags.DeclaredOnly);
		//foreach(MethodInfo info in methInfo)
		//{
		//	m_AllMethods.Add(info.Name);
		//}

		base.Awake();

		m_CardsOffsetY = GamesManager.Instance.ScreenHeight * m_CardsOffsetYPercentage;

		GameObject level;
		if(GamesManager.Instance.NbOfPlayers == 2)
		{
			level = (GameObject)Instantiate(m_LevelsForTwo[UnityEngine.Random.Range (0, m_LevelsForTwo.Length)]);
		}
		else
		{
			level = (GameObject)Instantiate(m_LevelsForThreeAndMore[UnityEngine.Random.Range (0, m_LevelsForThreeAndMore.Length)]);
		}
		level.transform.parent = transform;

		if(m_CurrentObjectives == m_ObjectivesIDEnum.NONE)
		{
			SetRandomObjective();
		}

		m_TurnsLeft = UnityEngine.Random.Range (5, 11);
		//m_TurnsLeft = UnityEngine.Random.Range (0, 0);
		SetTurnsLeftText();

		SetupBases();
		SetObjectiveText();

		m_CurrentObjectives = m_ObjectivesIDEnum.COLLECTCOINS;

		if(m_CurrentObjectives == m_ObjectivesIDEnum.COLLECTCOINS)
		{
			int coinsToCreate = GamesManager.Instance.NbOfPlayers * 2;
			if(coinsToCreate + GamesManager.Instance.NbOfPlayers >= m_AllSquares.Count)
			{
				coinsToCreate = m_AllSquares.Count - GamesManager.Instance.NbOfPlayers;
			}
			CreateCoins(coinsToCreate);
		}
		else if(m_CurrentObjectives == m_ObjectivesIDEnum.MOSTKILLS)
		{

		}
	}

	private void Start () 
	{
		int nbOfPlayers = GamesManager.Instance.m_NbOfPlayers - GamesManager.Instance.m_NbOfCPU;
		for(int i = 0; i < GamesManager.Instance.NbOfPlayers; i++)
		{
			GameObject lastPlayer = (GameObject)Instantiate(m_PlayerPrefab);
			lastPlayer.transform.parent = transform;
			TroublePlayer player = lastPlayer.GetComponent<TroublePlayer>();
			player.PlayerOrder = i;

			if(i == 0)
			{
				m_CurrentPlayer = player;
			}

			if(i < nbOfPlayers)
			{
			}
			else
			{
				player.IsComputer = true;
			}

			player.aTransform.GetChildByName("PlayerIcon").GetComponent<SpriteRenderer>().sprite = GamesManager.Instance.m_PlayersIcon[UnityEngine.Random.Range(0, GamesManager.Instance.m_PlayersIcon.Length)];

			Transform baseChosen = m_AllBases[i].transform.GetChildByName("Base");
			player.transform.position = baseChosen.position;
			player.CurrentSquare = baseChosen.GetComponent<EmptySquare>();
			player.PlayerInitialBase = player.CurrentSquare as PlayerBase;
			m_Players.Add (player);
			
			// Temp Visual Color
			if(i == 0)
			{
				player.PlayerColor = Color.blue;
				baseChosen.gameObject.GetComponent<SpriteRenderer>().material.color = player.PlayerColor;
				player.renderer.material.color = player.PlayerColor;
			}
			else if(i == 1)
			{
				player.PlayerColor = Color.red;
				baseChosen.gameObject.renderer.material.color = player.PlayerColor;
				player.renderer.material.color = player.PlayerColor;
			}
			else if(i == 2)
			{
				player.PlayerColor = Color.yellow;
				baseChosen.gameObject.renderer.material.color = player.PlayerColor;
				player.renderer.material.color = player.PlayerColor;
			}
			else if(i == 3)
			{
				player.PlayerColor = Color.gray;
				baseChosen.gameObject.renderer.material.color = player.PlayerColor;
				player.renderer.material.color = player.PlayerColor;
			}
		}

		OnNewTurn();
		SetObjectiveScore();
	}

	private void Update () 
	{
		if(m_CardsList.Count > 0)
		{
			UpdateCardsPosition();
		}
		//Vector3.
		//m_CardsList[1].transform.position = Vector3.MoveTowards(m_CardsList[1].transform.position, m_CardsList[0].transform.position, 2.5f * Time.deltaTime);

		if(m_CurrentPlayer.IsComputer && !m_GameOver)
		{
			OnCPUTurn();
		}
	
		//m_CardsList[1].transform.position = Vector3.Lerp(m_CardsList[1].transform.position, m_CardsList[0].transform.position, 0.5f * Time.deltaTime);
	}

	private void OnCPUTurn()
	{
		if(m_CanClick && m_CurrentPlayer.CPUCanPlay && !m_CurrentCard)
		{
			m_CurrentPlayer.CPUCanPlay = false;
			int randomCard = Random.Range (0, m_CardsList.Count);
			m_CardsList[randomCard].OnCardClicked();
		}
	}

	private void SetRandomObjective()
	{
		int randomObjective = UnityEngine.Random.Range (1, (int)m_ObjectivesIDEnum.OBJECTIVESEND);
		m_CurrentObjectives = (m_ObjectivesIDEnum)randomObjective;
	}

	private void SetObjectiveScore()
	{
		for(int i = 0; i < GamesManager.Instance.NbOfPlayers; i++)
		{
			GameObject iconScore = (GameObject)Instantiate(m_IconScorePrefab);
			Transform iconTransform = iconScore.transform;
			if(i == 0)
			{
				iconTransform.GetChildByName("CurrentTurnVisual").gameObject.SetActive(true);
			}
			iconScore.GetComponent<SpriteRenderer>().sprite = m_Players[i].aTransform.GetChildByName("PlayerIcon").GetComponent<SpriteRenderer>().sprite;
			iconTransform.parent = transform;
			Vector3 newPos = new Vector3(GamesManager.Instance.ScreenWidth * 0.74f, (GamesManager.Instance.ScreenHeight * 0.84f) - (i * iconTransform.localScale.y));
			iconTransform.position = newPos;
			iconTransform.GetChildByName("PlayerOrderText").GetComponent<TextMesh>().text = "P" + (i + 1) + " - ";
			iconTransform.GetChildByName("GenericRectangle").GetComponent<SpriteRenderer>().material.color = m_Players[i].PlayerColor;

			m_IconScore.Add (iconScore);
		}
	}

	private void SetObjectiveText()
	{
		switch(m_CurrentObjectives)
		{
		case m_ObjectivesIDEnum.COLLECTCOINS:
			m_ObjectivesText.text = "OBJECTIVES:\nCOLLECT COINS!";
			break;
		case m_ObjectivesIDEnum.MOSTKILLS:
			m_ObjectivesText.text = "OBJECTIVES:\nMOST KILLS!";
			break;
		//case m_ObjectivesIDEnum.CAPTUREBASE:
		//	m_ObjectivesText.text = "OBJECTIVES:\nCAPTURE BASE!";
		//	break;
		default:
			break;
		}
	}
	
	private void SetTurnsLeftText()
	{
		m_TurnsLeftText.text = m_TurnsLeft.ToString();
	}

	private void SetupBases()
	{
		List<int> baseID = new List<int>();
		GameObject currentBases = GameObject.FindGameObjectWithTag("Bases");
		for(int i = 0; i < currentBases.transform.childCount; i++)
		{
			baseID.Add (i);
		}

		List<int> randChosen = new List<int>();
		for(int i = 0; i < GamesManager.Instance.NbOfPlayers; i++)
		{
			int randomBaseChosen = UnityEngine.Random.Range(0, baseID.Count);
			
			randChosen.Add (baseID[randomBaseChosen]);
			m_AllBases.Add (currentBases.transform.GetChild(baseID[randomBaseChosen]).gameObject);

			baseID.RemoveAt(randomBaseChosen);
		}
		
		for(int i = 0; i < currentBases.transform.childCount; i++)
		{
			bool found = false;
			int j = 0;
			for(j = 0; j < randChosen.Count; j++)
			{
				if(i == randChosen[j])
				{
					found = true;
					break;
				}
			}
			
			if(!found)
			{
				Transform baseToDelete = currentBases.transform.GetChild(i);
				for(int k = 0; k < baseToDelete.childCount; k++)
				{
					Transform squareToDelete = baseToDelete.GetChild(k);
					if(squareToDelete.name != "Base")
					{
						EmptySquare squareToRemove = squareToDelete.GetComponent<EmptySquare>();
						m_AllSquares.RemoveAt(squareToRemove.ListID);
						for(int l = squareToRemove.ListID; l < m_AllSquares.Count; l++)
						{
							m_AllSquares[l].ListID--;
						}
					}
				}
				Destroy(currentBases.transform.GetChild(i).gameObject);
			}
		}
	}
	
	public void CreateCoins(int coinsToCreate = 1)
	{
		for(int i = 0; i < coinsToCreate; i++)
		{
			int randIndex = UnityEngine.Random.Range(0, m_AllSquares.Count);
			EmptySquare randSquare = m_AllSquares[randIndex];

			int maxLoop = 60;
			while(randSquare.SomethingOver)
			{
				if(randIndex == 0)
				{
					randIndex = m_AllSquares.Count;
				}
				randIndex--;
				randSquare = m_AllSquares[randIndex];

				maxLoop--;
				if(maxLoop <= 0)
				{
					break;
				}
			}

			randSquare.SomethingOver = true;

			GameObject go = (GameObject)Instantiate(m_Coins);
			go.transform.parent = transform;
			go.transform.position = randSquare.aTransform.position;

			TroubleCoin coin = go.GetComponent<TroubleCoin>();
			coin.OverSquare = randSquare;
			randSquare.SquareValue = coin.CoinValue;
		}
	}

	private void UpdateCardsPosition()
	{
		bool allDone = true;
		for(int i = 0; i < m_CardsList.Count; i++)
		{
			if(m_CardsList[i].aTransform.position != m_CardsList[i].TargetPos)
			{
				m_CardsList[i].aTransform.position =  Vector3.MoveTowards(m_CardsList[i].aTransform.position, m_CardsList[i].TargetPos, m_CardsPositionSpeed * Time.deltaTime);
				allDone = false;
			}
		}

		if(allDone)
		{
			if(!m_ExitAnimDone)
			{
				if(!m_EntranceAnimDone)
				{
					m_EntranceAnimDone = true;
					ShuffleAndPosition();
				}
				else
				{
					if(!m_CanClick)
					{
						m_CanClick = true;
					}
				}
			}
			else
			{
				if(!m_CanDestroyCards)
				{
					for(int i = 0; i < m_CardsList.Count; i++)
					{
						m_CardsList[i].TargetPos = m_CardsList[i].InitialPos;
					}
				}
				else
				{
					OnTurnEnd();
					return;
				}
				m_CanDestroyCards = true;
			}
		}
	}

	private void OnNewTurn()
	{
		m_CurrentCard = null;
		m_CanClick = false;
		m_EntranceAnimDone = false;
		m_ExitAnimDone = false;
		m_CanDestroyCards = false;
		m_TurnEnded = false;
		PlayerToPlay();
	}

	private void PlayerToPlay()
	{
		m_PlayerTurnText.GetComponent<TextMesh>().text = "P" + (m_CurrentTurn + 1).ToString() + "'s Turn";
		m_PlayerTurnText.transform.GetChildByName("GenericRectangle").GetComponent<SpriteRenderer>().material.color = m_Players[m_CurrentTurn].PlayerColor;
		m_PlayerTurnText.GetComponent<Animator>().SetTrigger("OnNewTurn");
	}

	private void OnTurnEnd()
	{		
		for(int i = 0; i < m_CardsList.Count; i++)
		{
			Destroy(m_CardsList[i].aGameObject);
		}
		m_CardsList = new List<TroubleCard>();

		m_IconScore[m_CurrentTurn].transform.GetChildByName("CurrentTurnVisual").gameObject.SetActive(false);

		m_CurrentPlayer.CurrentSquare.SquareValue = 4;

		m_CurrentTurn++;
		if(m_CurrentTurn > m_Players.Count - 1)
		{
			m_CurrentTurn = 0;
			OnAllTurnEnd();
		}

		m_CurrentPlayer = m_Players[m_CurrentTurn];

		if(!m_GameOver)
		{
			m_IconScore[m_CurrentTurn].transform.GetChildByName("CurrentTurnVisual").gameObject.SetActive(true);
			OnNewTurn();
		}
	}

	private void OnAllTurnEnd()
	{
		m_TurnsLeft--;
		if(m_TurnsLeft < 0)
		{
			//List<TroublePlayer> winners = new List<TroublePlayer>();
			//for(int i = 0; i < m_Players.Count; i++)
			//{
			//	//if(winner.CurrentPoints
			//}
			OnGameOver(CheckWinners());
		}
		else
		{
			SetTurnsLeftText();
		}
	}

	private List<TroublePlayer> CheckWinners()
	{
		TroublePlayer highestScore = m_Players[0];
		for(int i = 0; i < m_Players.Count; i++)
		{
			if(m_Players[i].CurrentPoints > highestScore.CurrentPoints)
			{
				highestScore = m_Players[i];
			}
		}

		List<TroublePlayer> allWinners = new List<TroublePlayer>();
		for(int i = 0; i < m_Players.Count; i++)
		{
			if(m_Players[i].CurrentPoints == highestScore.CurrentPoints)
			{
				allWinners.Add (m_Players[i]);
			}
		}

		return allWinners;
	}

	public void CreateCard()
	{
		int randomNumber = UnityEngine.Random.Range(m_CardsMinValue, m_CardsMaxValue);

		for(int i = 0; i < m_CardsNumber; i++)
		{
			GameObject lastCard = (GameObject)Instantiate(m_CardPrefab);
			lastCard.transform.position = new Vector3(0f, 
			                                          (GamesManager.Instance.ScreenHeight + lastCard.transform.localScale.y), 
			                                          0f);
			TroubleCard card = lastCard.GetComponent<TroubleCard>();
			card.CardValue = randomNumber;
			card.TargetPos = new Vector3(	0f, 
			                       			m_CardsOffsetY, 
			                             	0f);
			card.InitialPos = lastCard.transform.position;

			m_CardsList.Add (card);

			randomNumber++;
			if(randomNumber > m_CardsMaxValue)
			{
				randomNumber = m_CardsMinValue;
			}

			m_RandomPosList.Add(i);
		}
	}

	private void ShuffleAndPosition()
	{
		int randomIndex;
		for(int i = 0; i < m_CardsList.Count; i++)
		{
			randomIndex = UnityEngine.Random.Range (0, m_RandomPosList.Count);
			switch(m_RandomPosList[randomIndex])
			{
			case 0:
				m_CardsList[i].TargetPos = new Vector3(	-2f, 
				                       					m_CardsOffsetY, 
				                                       1.5f);
				break;
			case 1:
				m_CardsList[i].TargetPos = new Vector3(	-1f, 
				                                       m_CardsOffsetY, 
				                                       1f);
				break;
			case 2:
				m_CardsList[i].TargetPos = new Vector3(	0, 
				                                       m_CardsOffsetY, 
				                                       0f);
				break;
			case 3:
				m_CardsList[i].TargetPos = new Vector3(	1f, 
				                                       m_CardsOffsetY, 
				                                       -0.5f);
				break;
			case 4:
				m_CardsList[i].TargetPos = new Vector3(	2f, 
				                                       m_CardsOffsetY, 
				                                       -1f);
				break;
			default:
				break;
			}

			m_RandomPosList.RemoveAt(randomIndex);
		}
	}

	private void CheckLastLanded()
	{
		for(int i = 0; i < m_Players.Count; i++)
		{
			if(i != m_CurrentTurn)
			{
				//if(m_Players[m_CurrentTurn].CurrentSquare == m_Players[i].PlayerInitialBase as EmptySquare)
				//{
				//	OnGameOver(m_Players[m_CurrentTurn]);
				//}
				m_Players[m_CurrentTurn].CurrentSquare.PlayerOver = true;
				if(m_Players[m_CurrentTurn].CurrentSquare == m_Players[i].CurrentSquare)
				{
					OnLandingOnOtherPlayer(m_Players[m_CurrentTurn], m_Players[i]);
					m_Players[i].aTransform.position = m_Players[i].PlayerInitialBase.aTransform.position;
					m_Players[i].CurrentSquare = m_Players[i].PlayerInitialBase;
				}
			}
		}
	}

	private void OnLandingOnOtherPlayer(TroublePlayer thisPlayer, TroublePlayer otherPlayer)
	{
		if(m_CurrentObjectives == m_ObjectivesIDEnum.COLLECTCOINS)
		{
			//int coinsToLose = (int)(Mathf.Ceil(otherPlayer.CurrentPoints/4.0f));
			int coinsToLose = otherPlayer.CurrentPoints >= 3 ? 3 : otherPlayer.CurrentPoints;
			thisPlayer.CurrentPoints += coinsToLose;
			otherPlayer.CurrentPoints -= coinsToLose;
			UpdateScoreText();
		}
		else if(m_CurrentObjectives == m_ObjectivesIDEnum.MOSTKILLS)
		{

		}
	}

	private void OnGameOver(List<TroublePlayer> winners)
	{
		m_GameOver = true;
		GameObject popup = (GameObject)Instantiate(m_PopupScreen);
		string winnersText = "";
		for(int i = 0; i < winners.Count; i++)
		{
			GameObject icon = (GameObject)Instantiate(winners[i].aTransform.GetChildByName("PlayerIcon").gameObject);
			float posX = icon.transform.localScale.x * i - ((winners.Count - 1)/2.0f);
			icon.GetComponent<SpriteRenderer>().sortingLayerName = "HUD";
			icon.GetComponent<SpriteRenderer>().sortingOrder = 5;
			icon.transform.position = new Vector3(posX, 2.25f, -4.1f);
			if(i == 0)
			{
				winnersText += ("P" + (winners[i].PlayerOrder + 1).ToString());
			}
			else
			{
				winnersText += (", P" + (winners[i].PlayerOrder + 1).ToString());
			}
		}
		
		popup.transform.position = new Vector3(0f, 0f, -4f);
		popup.transform.GetChildByName("WinnersText").GetComponent<TextMesh>().text = winnersText;
		if(winners.Count == 1)
		{
			popup.transform.GetChildByName("WinText").GetComponent<TextMesh>().text = "WINS!!!";
		}
		else
		{
			popup.transform.GetChildByName("WinText").GetComponent<TextMesh>().text = "WIN!!!";
		}
	}

	public void OnCardClicked(TroubleCard chosenCard)
	{
		m_CurrentCard = chosenCard;
		m_CanClick = false;
		m_MovesLeft = chosenCard.CardValue;
	}
	
	public void OnCardFlipReverseDone()
	{
		m_ExitAnimDone = true;
		for(int i = 0; i < m_CardsList.Count; i++)
		{
			m_CardsList[i].TargetPos = new Vector3(	0f, 
			                                       m_CardsOffsetY, 
			                                       0f);
		}
	}

	public void OnPlayerPositionChanged()
	{
		m_MovesLeft--;
		CurrentCard.UpdateTextMesh();
		if(m_MovesLeft <= 0)
		{
			CheckLastLanded();
			m_Players[m_CurrentTurn].ResetTileRenderer();
			if(!m_GameOver)
			{
				m_MovesLeft = 0;
				m_TurnEnded = true;
				CurrentCard.Animator.SetTrigger("TurnEnd");
			}
		}
	}

	public void UpdateScoreText()
	{
		for(int i = 0; i < m_IconScore.Count; i++)
		{
			m_IconScore[i].transform.GetChildByName("ScoreText").GetComponent<TextMesh>().text = m_Players[i].CurrentPoints.ToString();
		}
	}
}